/*
 by txdnet.cn tonydon
 *  2011.04.30
 */
package txdnet.util.image;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Locale;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import org.apache.commons.fileupload.FileItem;
import txdnet.util.FileUtil;
import txdnet.util.Logger;
import txdnet.util.StaticMark;

/**
 *
 * @author txdnet
 */
public class ImageUtil {

    private static Class clazz = ImageUtil.class;

    private ImageUtil() {
    }
    private static Font textfont = null;
    /*
     * 图像场景预处理
     * @param srcImg 图像源文件对象
     * @param width 新场景宽度
     * @param height 新场景高度
     * @param scaleType 创建场景取样类型 见Image字段
     */

    public static BufferedImage makeThumbSnap(BufferedImage srcImg, int width, int height) {
        int biType = srcImg.getType();
        BufferedImage tag;
        if (biType == BufferedImage.TYPE_CUSTOM) {
            tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        } else {
            ColorModel dstCM = srcImg.getColorModel();
            tag = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(width, height), dstCM.isAlphaPremultiplied(), null);
        }
        Graphics2D g = tag.createGraphics();
        g.drawImage(srcImg.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
        g.dispose();
        return tag;
    }

    public static BufferedImage filter(BufferedImage src, double rate) {
        int biType = src.getType();
        int w = (int) (src.getWidth() * rate);
        int h = (int) (src.getHeight() * rate);
        BufferedImage dst;
        if (biType == BufferedImage.TYPE_CUSTOM) {
            dst = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        } else {
            ColorModel dstCM = src.getColorModel();
            dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(w, h), dstCM.isAlphaPremultiplied(), null);
        }
        Graphics2D g = dst.createGraphics();
        g.drawImage(src.getScaledInstance(w, h, Image.SCALE_SMOOTH), 0, 0, w, h, null);
        g.dispose();
        return dst;
    }

    /*
     *  JPEG 压缩质量控制
     */
    public static boolean doJpegHandle(BufferedImage image, File distImg) {
        boolean flag = true;
        try {
            Iterator iter = ImageIO.getImageWritersByFormatName("jpeg");
            ImageWriter writer = (ImageWriter) iter.next();
            ImageOutputStream ios = ImageIO.createImageOutputStream(distImg);
            writer.setOutput(ios);
            ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());
            iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            iwparam.setCompressionQuality(0.91F);
            iwparam.setProgressiveMode(ImageWriteParam.MODE_DISABLED);
            writer.write(null, new IIOImage(image, null, null), iwparam);
            ios.flush();
            writer.dispose();
            ios.close();
        } catch (IOException e) {
            Logger.error(clazz, e.toString());
            flag = false;
        }
        return flag;
    }

    /**
     * 图片水印
     *
     * @param srcImg 元图片
     * @param tagImg 标志图片
     * @param alpha 透明度,默认在右下角
     */
    public static void pressImage(String srcImg, String tagImg, float alpha) {
        File img;
        BufferedImage src, image, srcMark;
        Graphics2D g;

        try {
            img = new File(srcImg);
            src = ImageIO.read(img);
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            g = image.createGraphics();
            g.drawImage(src, 0, 0, width, height, null);
            // 水印文件
            srcMark = ImageIO.read(new File(tagImg));
            int wb = srcMark.getWidth(null);
            int hb = srcMark.getHeight(null);
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            g.drawImage(srcMark, (width - wb), (height - hb), wb, hb, null);
            // 水印文件结束
            g.dispose();
            ImageIO.write(image, FileUtil.getFileExt(srcImg), img);
            image.flush();
            srcMark.flush();
        } catch (IOException ex) {
            Logger.error(clazz, ex.toString());
        }
    }

    /**
     * 文字水印
     *
     * @param pressText 水印文字
     * @param tagImg 目标图片
     * @param fontName 字体名称
     * @param fontStyle 字体样式
     * @param color 字体颜色
     * @param fontSize 字体大小
     * @param x 修正值
     * @param y 修正值
     * @param alpha 透明度
     */
    public static void pressText(
            String srcImg,
            String pressText,
            String fontName,
            int fontStyle,
            Color color,
            int fontSize,
            int x, int y, float alpha) {
        File img;
        BufferedImage src, image;
        Graphics2D g;
        try {
            img = new File(srcImg);
            src = ImageIO.read(img);
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            g = image.createGraphics();
            g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
            g.drawImage(src, 0, 0, width, height, null);
            g.setColor(color);
            // 判断是否采用文字文件
            if (fontName.indexOf(StaticMark.CHAR_SLASH) >= 0) {
                if (textfont == null) {
                    textfont = MyFont.getTureTypeFontByClass(clazz.getResourceAsStream(fontName)).deriveFont(fontStyle, fontSize);
                }
            } else {
                if (textfont == null) {
                    textfont = new Font(fontName, fontStyle, fontSize);
                }
            }
            g.setFont(textfont);
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            g.drawString(pressText, (width - ((pressText.length()) * fontSize)) / 2 + x, (height - fontSize) + y);
            g.dispose();
            ImageIO.write(image, FileUtil.getFileExt(srcImg), img);
            image.flush();
        } catch (IOException ex) {
            Logger.error(clazz, ex.toString());
        }
    }


    /*
     *  JPEG 老式缩图编码 效果不理想

     public static boolean resizeJPEG(File srcImg, File newImg, int width, int height) {
     BufferedImage bi = null;
     BufferedImage itemp = null;
     double ratio = 0; // 缩放比例
     boolean flag = true;
     int biType = 0;
     try {
     bi = ImageIO.read(srcImg);
     biType = bi.getType();
     // 比缩放长宽大
     if ((bi.getHeight() > height) || (bi.getWidth() > width)) {
     if (bi.getHeight() > bi.getWidth()) {
     ratio = ((double)height)/ bi.getHeight();
     } else {
     ratio = ((double)width) / bi.getWidth();
     }
     itemp = ImageUtil.filter(bi, ratio);
     }else{
     // 比缩放长宽都要小或者相等
     itemp = bi;
     }

     BufferedImage image = new BufferedImage(width, height, biType);
     Graphics2D g = image.createGraphics();
     g.setBackground(Color.white);
     g.setColor(Color.white);
     g.fillRect(0, 0, width, height);
     g.drawImage(itemp, (width - itemp.getWidth(null))>>1, (height - itemp.getHeight(null))>>1, itemp.getWidth(null), itemp.getHeight(null), null);
     g.dispose();
     itemp = image;
     BufferedOutputStream bos  = new BufferedOutputStream(new FileOutputStream(newImg));
     JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bos);
     JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(itemp);

     jep.setQuality(0.86f, true);
     encoder.encode(itemp, jep);
     itemp.flush();
     bos.close();
     } catch (IOException ex) {
     Logger.error(clazz, ex.toString());
     flag = false;
     }
     return flag;
     }
     */
    /**
     * 一个图片缩放函数 在原图上进行缩放 是否产生新缩放图 由outPath是否为null决定,非空则缩图为新文件.
     *
     * @param srcImg 图片路径
     * @param height 高度
     * @param width 宽度
     * @param isblank 是否居中并补白背景
     */
    public static boolean resize(String srcImg, String newImg, int width, int height, boolean isblank) {
        File sp = new File(srcImg);
        if (!sp.exists()) {
            return false;
        }
        File np = (newImg == null) ? sp : (new File(newImg));
        BufferedImage bi;
        BufferedImage itemp;
        int ow, oh, x, y;
        //  AffineTransformOp op = null;
        double ratio = 0; // 缩放比例
        boolean flag = true;
        String ext = FileUtil.getFileExt(srcImg);

        try {
            bi = ImageIO.read(sp);
            if ((bi.getHeight() > height) || (bi.getWidth() > width)) {
                if (bi.getHeight() > bi.getWidth()) {
                    ratio = ((double) height) / bi.getHeight();
                } else {
                    ratio = ((double) width) / bi.getWidth();
                }
            }
            // 比缩放长宽
            if (ratio < 1 && ratio > 0) {
                itemp = ImageUtil.filter(bi, ratio);
            } else {
                // 比缩放长宽都要小或者相等
                itemp = bi;
            }

            BufferedImage image;
            Graphics2D g;

            // 以下为补白居中处理
            if (isblank) {
                ow = width;
                oh = height;
                x = (width - itemp.getWidth(null)) >> 1;
                y = (height - itemp.getHeight(null)) >> 1;
                image = new BufferedImage(ow, oh, BufferedImage.TYPE_INT_RGB);
                g = image.createGraphics();
                g.setBackground(Color.white);
                g.setColor(Color.white);
                g.fillRect(0, 0, ow, oh);
                g.drawImage(itemp, x, y, itemp.getWidth(null), itemp.getHeight(null), null);
                g.dispose();
            } else {
                image = itemp;
            }

            // 单独处理 jpeg 图片
            if ("jpegjpg".contains(ext.toLowerCase())) {
                flag = ImageUtil.doJpegHandle(image, np);
            } else {
                // 处理PNG GIF BMP
                ImageIO.write(image, ext, np);
            }
            image.flush();
        } catch (IOException ex) {
            Logger.error(clazz, ex.toString());
            flag = false;
        }
        return flag;
    }

    // 补白居中等比缩图
    public static boolean resize(String srcImg, String newImg, int width, int height) {
        return ImageUtil.resize(srcImg, newImg, width, height, true);
    }

    /*
     * 切图方法
     * @param image 原始Image对象
     * @param subBounds 切图选区方形对象
     * @param subFile 切图输出文件对象
     * @param formatName 图片后缀类型
     */
    public static boolean saveSubImg(BufferedImage image, Rectangle subBounds, File subFile, String formatName) {
        BufferedImage subimg = new BufferedImage(subBounds.width, subBounds.height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = subimg.createGraphics();
        boolean flag = true;

        int left = subBounds.x;
        int top = subBounds.y;
        int uleft = Math.abs(left);
        int utop = Math.abs(top);
        int imgW = image.getWidth();
        int imgH = image.getHeight();
        int sW = subBounds.width;
        int sH = subBounds.height;
        try {
            if (left >= 0 && top >= 0 && imgW - left >= sW && imgH - top >= sH) {
                g.drawImage(image.getSubimage(left, top, sW, sH), 0, 0, null);
            } else if (left >= 0 && top >= 0 && ((imgW - left) < sW || (imgH - top) < sH)) {
                g.setBackground(Color.white);
                g.fillRect(0, 0, sW, sH);// 填充矩形场景
                g.drawImage(image, -left, -top, Color.white, null);
            } else if (left < 0 || top < 0) {
                if (sW > imgW) {
                    if ((sW - imgW) > uleft) {
                        left = (sW - imgW) >> 1;
                    } else {
                        left = uleft;
                    }
                } else if (left < 0) {
                    left = uleft;
                } else {
                    left = (-left);
                }
                if (sH > imgH) {
                    if ((sH - imgH) > utop) {
                        top = (sH - imgH) >> 1;
                    } else {
                        top = utop;
                    }
                } else if (top < 0) {
                    top = utop;
                } else {
                    top = (-top);
                }
                g.setBackground(Color.white);
                g.fillRect(0, 0, sW, sH);// 填充矩形场景
                g.drawImage(image, left, top, Color.white, null);
            }
            g.dispose();
            if ("jpegjpg".contains(formatName.toLowerCase())) {
                flag = ImageUtil.doJpegHandle(subimg, subFile);
            } else {
                ImageIO.write(subimg, formatName, subFile);
            }
            subimg.flush();
        } catch (IOException e) {
            Logger.error(clazz, e.toString());
            flag = false;
        } finally {
            return flag;
        }
    }

    /*
     *  切图实现
     * @param srcFile 源图片文件对象
     * @param distFile 分发图片文件对象
     * @param width 原图片新场景宽
     * @param height 原图片新场景高
     * @param cutLeft 选框左边离新场景图片左边边距
     * @param cutTop 选框顶部离新场景图片顶部边距
     * @param dropWidth 选框宽度
     * @param dropHeight 选框高度
     */
    public static boolean cutImage(File srcFile, File distFile, int width, int height, int cutLeft, int cutTop, int dropWidth, int dropHeight) {

        boolean flag = true;
        try {
            flag = ImageUtil.saveSubImg(
                    ImageUtil.makeThumbSnap(ImageIO.read(srcFile), width, height), new Rectangle(cutLeft, cutTop, dropWidth, dropHeight), distFile, FileUtil.getFileExt(srcFile.getName()));
        } catch (IOException e) {
            Logger.error(clazz, e.toString());
            flag = false;
        } finally {
            return flag;
        }
    }


    /*
     * 检测图片合法性
     */
    public static boolean isImage(InputStream in) {
        ImageInfo ii = new ImageInfo();
        boolean flag ;
        ii.setInput(in);
        try {
            flag = ii.check();
        } catch (IOException e) {
            Logger.error(clazz, e.toString());
            flag = false;
        }
        return flag;
    }

    /*
     *  检查上传图片类型
     */
    public static boolean checkImage(final FileItem item) {
        BufferedImage bi;
        try {
            bi = ImageIO.read(item.getInputStream());
        } catch (IOException e) {
            Logger.error(clazz, e.toString());
            return false;
        }
        return (bi != null);
    }
}